package com.myk.game.gobangchess.rooms;

import com.myk.game.gobangchess.*;
import com.myk.game.gobangchess.constants.ColorCost;
import com.myk.game.gobangchess.constants.WinMode;
import com.myk.game.gobangchess.rooms.absrooms.AbsChessRoom;
import com.myk.game.gobangchess.signs.*;
import com.myk.game.gobangchess.utils.DateTimeUtil;
import com.myk.game.gobangchess.utils.GridsUtils;

import java.security.PublicKey;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 速弈王途（加速升王棋）
 * <p>
 * 设计速录
 * 1，规则还是要改回，移动的那个棋子如果速度最大直接成王。（为了增加开局时候的顺畅度，以及避免后排养猪，增加兑子战术的风险）（存疑，要看看对2v2残局的体验有没有影响？）
 * <p>
 * 2，速度低于2时只能直线走。（存疑，要看速度差为2时单对单能否杀死，否则没有必要）
 * 3，然后提示选王的gameTip要清理了。
 * <p>
 * 4，双方都只剩一个棋子的时候增加求和按钮。（要确认1v1速差为2时是否能将死，2v1是否存在将不死的情况）
 * <p>
 * 5，速度超过6变回1的目的是让线下骰子也能玩，配合8x8大小棋盘，棋子刚好不能走满全场避免被说是后。避免了后期抓不死的情况，同时避免了无限膨胀的速度导致理论上的bug。
 * （核心机制不可擅动）
 * <p>
 * 6，王不能吃对方非王棋子，是为了避免王过于强大不可被抓和避免王拥有过强的poke能力。（有更好方案时可该）
 */
public class SuYiWangTuChessRoom extends AbsChessRoom {

    private CacheSign cacheSign; //缓存标记
    private List<Chess> chessList; //场上棋子集合
    private Chess choose; //当前选中的棋子
    private Chess blackKing; //黑方王棋子
    private Chess whiteKing; //白方王棋子
    private List<Chess> candidates; //候选者们
    private int[] moveArrow;//移动箭头状态

    //最大移速，超过这个数再次移动速度会变回1，然后重新选王
    private static final int MAX_SP = 6;

    public SuYiWangTuChessRoom(String roomName) {
        super(roomName, "原作BGA上alek erickson的《Lielow》，江柯对其规则进行了改版。该棋目前处于试验状态，体验不好就会删除。", "速弈王途", GridsUtils.createEmptyGrids(8, 8), true, true);
        initChessBoardStyle();
    }

    //初始化棋盘样式
    private void initChessBoardStyle() {
        List<Sign> chessboardStyle = new ArrayList<>();
        int row = curGrids.length;
        int col = curGrids[0].length;
        //绘制类似国际象棋的黑白相间的格子
        List<Integer> bGrids = new ArrayList<>();
        List<Integer> wGrids = new ArrayList<>();
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                int index = getIndex(i, j);
                if ((i + j) % 2 == 0) {
                    bGrids.add(index);
                }
                else {
                    wGrids.add(index);
                }
            }
        }
        chessboardStyle.add(new ColorSign(bGrids, "#FF888888"));
        chessboardStyle.add(new ColorSign(wGrids, "#FFDDDDDD"));
        //画棕色外边框
        chessboardStyle.add(new GroundSign(getIndex(0, 0), getIndex(row - 1, col - 1), "#00000000", "#FF333333", 2.2f, 0, 0));
        //将背景封装为缓存标记
        cacheSign = new CacheSign(this, "background", 3, true, chessboardStyle); //*** 修改背景样式记得改这里的版本号！！！
    }

    @Override
    public String getRuleText() {
        return "{{《速弈王途》加速升王棋@color=#000000@scale=1.5}}\n" +
                "{{棋盘与棋子：@color=#000000@scale=1.2}}\n" +
                "    {{8x8棋盘，双方各有8枚棋子。@color=#0099BB}}\n" +
                "    {{初始移动速度为1，排列在双方底线一行。@color=#0099BB}}\n" +
                "{{移动规则：@color=#000000@scale=1.2}}\n" +
                "    {{棋子移动后速度增加1，移速超过6时会变回1。@color=#0099BB}}\n" +
                "    {{速度等于1时按照国象中“车”的方式移动和吃子，但距离只能为1，@color=#0099BB}}\n" +
                "    {{速度大于1时按照国象中“后”的方式移动和吃子，距离不能超过移速。@color=#0099BB}}\n" +
                "{{成王规则：@color=#000000@scale=1.2}}\n" +
                "    {{移动或吃子后，若该棋子速度达到己方最大值，直接变成王，@color=#0099BB}}\n" +
                "    {{移动或吃子后，若该棋子速度变回1，选择一枚己方移速最大的棋子变成王。@color=#0099BB}}\n" +
                "    {{双方各自只能有一个王。@color=#0099BB}}\n" +
                "{{吃子规则：@color=#000000@scale=1.2}}\n" +
                "    {{棋子成王后只能吃对方的王，不能吃其它棋子。@color=#0099BB}}\n" +
                "{{胜利条件：@color=#000000@scale=1.2}}\n" +
                "    {{吃掉对方的王即获胜。@color=#0099BB}}";
    }

    @Override
    protected void onStartPrepare() {
        initSiders();//游戏开始的时候初始化棋子和布局
        noticeBlackMove();
    }

    @Override
    public void resetGrids() {
        step = 0;
        gameTip = "-1";
        curGrids = GridsUtils.copyGrids(originGrids);
        signList.clear();
        chessList = null;
        choose = null;
        blackKing = null;
        whiteKing = null;
        candidates = null;
        moveArrow = null;
    }

    @Override
    public void doRule(int row, int col, int value) {
        if (candidates != null) { //处于待选新王状态时
            Chess chess = getChessByPos(row, col);
            if (chess != null && chess.isSameSide(value) && candidates.contains(chess)) { //选中待选新王
                doChooseNewKing(chess, value);
            }
        }
        else if (choose == null || !choose.isSameSide(value)) { //还未选择目标时
            Chess chess = getChessByPos(row, col);
            if (chess != null && chess.isSameSide(value)) {
                moveArrow = null; //以免标记太多碍眼
                choose = chess;//选中己方棋子
                noticeAllRefreshGameInfo(); //仅仅刷新显示，还能继续点击
            }
        }
        else { //已经选中棋子了
            List<Integer> canMovedPos = choose.getCanMovedPos(); //选中棋子的可移动路线
            if (canMovedPos.contains(getIndex(row, col))) { //可以移动到目标位置
                //吃子判定
                Chess chess = getChessByPos(row, col);
                if (chess != null) {
                    doEatChess(chess, value); //执行吃子操作
                }
                else {
                    doChessMove(row, col, value);//执行移动操作
                }
            }
            else { //目标位置不能移动到
                Chess chess = getChessByPos(row, col);
                if (chess != null && chess.isSameSide(value)) {
                    choose = chess;//切换选中己方棋子
                    noticeAllRefreshGameInfo(); //仅仅刷新显示，还能继续点击
                }
                else {
                    choose = null;
                    noticeAllRefreshGameInfo(); //仅仅刷新显示，还能继续点击
                }
            }
        }
    }

    @Override
    public String getGameInfo() {
        //先全部初始化
        curGrids = GridsUtils.copyGrids(originGrids);
        signList.clear();
        signList.add(cacheSign);

        //根据chessList集合和choose对象来生成要显示到客户端的布局和标记
        if (chessList != null && chessList.size() > 0) {
            //绘制棋子
            for (Chess chess : chessList) {
                curGrids[chess.pRow][chess.pCol] = chess.getValue(); //显示棋子的底座
                signList.add(new TextSign(getIndex(chess.pRow, chess.pCol), chess.mSpeed + "", chess.getColor())); //显示棋子的文字
            }
            //绘制对弈时的选中棋子移动状态
            if (choose != null) {
                //绘制棋子可移动路径
                List<Integer> canMovedPosList = choose.getCanMovedPos(); //获取该棋子可移动到的格子的坐标集合
                if (canMovedPosList.size() > 0) {
                    signList.add(new ColorSign(canMovedPosList, "#9988EE88")); //可移动到的格子用更淡的绿色表示
                }
                //绘制棋子选中状态
                signList.add(new GroundSign(getIndex(choose.pRow, choose.pCol), "#00FFFFFF", "#FF33CC33", 2F, 0, 1));
            }
            //绘制待选新王列表
            if (candidates != null) {
                gameTip = "从这些高亮棋子中选择一个成为新王";
                for (Chess candidate : candidates) {
                    signList.add(new AroundSign(getIndex(candidate.pRow, candidate.pCol), "#33FFCC33", "#99FFCC33", 1F));
                }
            }
            else {
                if (gameTip.equals("从这些高亮棋子中选择一个成为新王")) {
                    gameTip = "-1";
                }
            }
            //绘制对弈时的箭头标记
            if (moveArrow != null && moveArrow.length == 3) {
                signList.add(new LineSign(moveArrow[0], moveArrow[1], "#9988EE88", 1)); //淡绿色箭头
            }
        }
        return super.getGameInfo();
    }

    @Override
    public CacheSign getCacheSignByName(String cacheName) {
        return cacheSign;
    }

    //初始化对弈双方的元数据
    private void initSiders() {
        chessList = new ArrayList<>();
        int w = curGrids[0].length;
        int row = curGrids.length - 1;
        for (int i = 0; i < w; i++) {
            chessList.add(new Chess(this, 1, 0, i));
            chessList.add(new Chess(this, 2, row, i));
        }
        choose = null;
    }

    //执行棋子移动操作
    private void doChessMove(int row, int col, int value) {
        moveArrow = new int[]{getIndex(choose.pRow, choose.pCol), getIndex(row, col), choose.mSide};
        choose.pRow = row;
        choose.pCol = col;
        choose.mSpeed++; //加速
        if (choose.mSide == 1) {
            if (blackKing == null) { //开局第一步才会没有王
                choose.isKing = true;
                blackKing = choose;
            }
            else if (choose != blackKing && choose.mSpeed == blackKing.mSpeed) { //棋子速度达到己方最大值(王肯定是最大值)，直接变成王
                blackKing.isKing = false;
                choose.isKing = true;
                blackKing = choose;
            }
            else if (choose.mSpeed > MAX_SP) { //移速超过上限了（移动后速度为1只能是超限了）
                choose.mSpeed = 1; //变回1
                choose.isKing = false; //变回普通棋子
                blackKing.isKing = false;
                blackKing = null; //此时没有王了
                List<Chess> cdts = getCandidates(choose);//获取所有可以成为king的棋子（肯定至少有一个棋子）
                if (cdts.size() > 1) {
                    candidates = cdts; //获取所有可以成为king的棋子
                    choose = null;
                    noticeAllRefreshGameInfo(); //继续行动选王
                    return;
                }
                else { //待选成王的棋子只有一个时直接成为王，不用手动选
                    Chess newKing = cdts.get(0);
                    newKing.isKing = true;
                    blackKing = newKing;
                }
            }
            else if (choose.mSpeed > blackKing.mSpeed) {
                blackKing.isKing = false;
                choose.isKing = true;
                blackKing = choose;
            }
        }
        else {
            if (whiteKing == null) {
                choose.isKing = true;
                whiteKing = choose;
            }
            else if (choose != whiteKing && choose.mSpeed == whiteKing.mSpeed) {
                whiteKing.isKing = false;
                choose.isKing = true;
                whiteKing = choose;
            }
            else if (choose.mSpeed > MAX_SP) {
                choose.mSpeed = 1; //变回1
                choose.isKing = false;
                whiteKing.isKing = false;
                whiteKing = null;
                List<Chess> cdts = getCandidates(choose);
                if (cdts.size() > 1) {
                    candidates = cdts;
                    choose = null;
                    noticeAllRefreshGameInfo(); //继续行动选王
                    return;
                }
                else {
                    Chess newKing = cdts.get(0);
                    newKing.isKing = true;
                    whiteKing = newKing;
                }
            }
            else if (choose.mSpeed > whiteKing.mSpeed) {
                whiteKing.isKing = false;
                choose.isKing = true;
                whiteKing = choose;
            }
        }
        stepAdd();
        choose = null;
        changeMove(value); //切换移动方
    }

    //执行吃子操作
    private void doEatChess(Chess chess, int value) {
        chessList.remove(chess); //暂时先从列表中移除，避免判定和绘制干扰
        if (chess.isKing) { //被吃的棋子是王直接获胜
            if (chess.mSide == 1) {
                doEatKing(chess);
                doOver(WinMode.WHITE_WIN, player_white.getNickNameOrTemp() + "吃掉黑方的王获胜！");
                return;
            }
            else {
                doEatKing(chess);
                doOver(WinMode.BLACK_WIN, player_black.getNickNameOrTemp() + "吃掉白方的王获胜！");
                return;
            }
        }
        int count = 0;
        for (Chess che : chessList) {
            if (che.mSide == chess.mSide) {
                count++;
            }
        }
        if (count == 0) {
            if (chess.mSide == 1) {
                doEatKing(chess);
                doOver(WinMode.WHITE_WIN, player_white.getNickNameOrTemp() + "吃光黑方所有棋获胜！");
            }
            else {
                doEatKing(chess);
                doOver(WinMode.BLACK_WIN, player_black.getNickNameOrTemp() + "吃光白方所有棋获胜！");
            }
        }
        else {
            doChessMove(chess.pRow, chess.pCol, value);
        }
    }

    //吃王操作
    private void doEatKing(Chess chess) {
        chessList.add(chess); //加回列表用于显示
        moveArrow = new int[]{getIndex(choose.pRow, choose.pCol), getIndex(chess.pRow, chess.pCol), choose.mSide}; //绘制吃掉的箭头
        choose = null;
        stepAdd();
    }

    //遴选新王操作
    private void doChooseNewKing(Chess newKing, int value) {
        newKing.isKing = true;
        if (value == 1) {
            blackKing = newKing;
        }
        else {
            whiteKing = newKing;
        }
        candidates = null;
        stepAdd();
        changeMove(value); //切换移动方
    }

    //根据坐标搜索棋子
    private Chess getChessByPos(int row, int col) {
        for (Chess chess : chessList) {
            if (chess.pRow == row && chess.pCol == col) {
                return chess;
            }
        }
        return null;
    }

    //获取所有待选成king的棋子集合
    private List<Chess> getCandidates(Chess choose) {
        List<Chess> list = new ArrayList<>();
        int max = choose.mSpeed;
        for (Chess chess : chessList) {
            if (chess.mSide == choose.mSide) {
                if (chess.mSpeed == max) {
                    list.add(chess);
                }
                else if (chess.mSpeed > max) {
                    list.clear();
                    list.add(chess);
                    max = chess.mSpeed;
                }
            }
        }
        return list;
    }

    //切换移动方
    private void changeMove(int value) {
        if (value == 1) {
            noticeWhiteMove();
        }
        else {
            noticeBlackMove();
        }
    }

    /**
     * 棋子类
     */
    private static class Chess {
        Room room;
        private final int mSide; //归属黑棋还是白棋 1黑  2白
        int mSpeed; //棋子的移动速度
        int pRow; //在棋盘上的横坐标
        int pCol; //在棋盘上的纵坐标
        boolean isKing; //是否为王

        public Chess(Room room, int mSide, int pRow, int pCol) {
            this.room = room;
            this.mSide = mSide;
            this.mSpeed = 1;
            this.pRow = pRow;
            this.pCol = pCol;
        }

        public int getValue() {
            if (mSide == 1) {
                if (isKing) {
                    return 11;
                }
                else {
                    return 1;
                }
            }
            else {
                if (isKing) {
                    return 12;
                }
                else {
                    return 2;
                }
            }
        }

        public String getColor() {
            if (isKing) {
                return "#FFFFCC33";
            }
            else {
                if (mSide == 1) {
                    return "#FFFFFFFF";
                }
                else {
                    return "#FF000000";
                }
            }
        }

        private boolean isSameSide(int value) {
            if (mSide == 1) {
                return value == 1 || value == 11;
            }
            else {
                return value == 2 || value == 12;
            }
        }

        private boolean checkAddToCanMovedPosList(List<Integer> canMovedPosList, int row, int col, int value) {
            if (value == 0) { //为空
                canMovedPosList.add(room.getIndex(row, col)); //加入路径
                return false; //还能继续搜索
            }
            else if (isSameSide(value)) { //同方棋子
                return true; //应该打断搜索
            }
            else { //异方棋子
                if (isKing) {
                    if (value == 11 || value == 12) { //对方的王
                        canMovedPosList.add(room.getIndex(row, col)); //加入列表（可以吃）
                    }
                }
                else {
                    canMovedPosList.add(room.getIndex(row, col)); //加入列表（可以吃）
                }
                return true; //应该打断搜索
            }
        }

        //获取可移动范围列表
        public List<Integer> getCanMovedPos() {

            List<Integer> canMovedPosList = new ArrayList<>();
            int h = room.curGrids.length;
            int w = room.curGrids[0].length;
            //向上搜索
            for (int i = pRow - 1, count = 0; i >= 0 && count < mSpeed; i--, count++) {
                int nRow = i;
                int nCol = pCol;
                int value = room.curGrids[nRow][nCol];
                if (checkAddToCanMovedPosList(canMovedPosList, nRow, nCol, value)) {
                    break;
                }
            }
            //向下搜索
            for (int i = pRow + 1, count = 0; i < h && count < mSpeed; i++, count++) {
                int nRow = i;
                int nCol = pCol;
                int value = room.curGrids[nRow][nCol];
                if (checkAddToCanMovedPosList(canMovedPosList, nRow, nCol, value)) {
                    break;
                }
            }
            //向左搜索
            for (int i = pCol - 1, count = 0; i >= 0 && count < mSpeed; i--, count++) {
                int nRow = pRow;
                int nCol = i;
                int value = room.curGrids[nRow][nCol];
                if (checkAddToCanMovedPosList(canMovedPosList, nRow, nCol, value)) {
                    break;
                }
            }
            //向右搜索
            for (int i = pCol + 1, count = 0; i < w && count < mSpeed; i++, count++) {
                int nRow = pRow;
                int nCol = i;
                int value = room.curGrids[nRow][nCol];
                if (checkAddToCanMovedPosList(canMovedPosList, nRow, nCol, value)) {
                    break;
                }
            }
            //移速超过1时才能斜向行走
            if (mSpeed > 1) {
                //向左上搜索
                for (int i = pRow - 1, j = pCol - 1, count = 0; i >= 0 && j >= 0 && count < mSpeed; i--, j--, count++) {
                    int nRow = i;
                    int nCol = j;
                    int value = room.curGrids[nRow][nCol];
                    if (checkAddToCanMovedPosList(canMovedPosList, nRow, nCol, value)) {
                        break;
                    }
                }
                //向右上搜索
                for (int i = pRow - 1, j = pCol + 1, count = 0; i >= 0 && j < w && count < mSpeed; i--, j++, count++) {
                    int nRow = i;
                    int nCol = j;
                    int value = room.curGrids[nRow][nCol];
                    if (checkAddToCanMovedPosList(canMovedPosList, nRow, nCol, value)) {
                        break;
                    }
                }
                //向左下搜索
                for (int i = pRow + 1, j = pCol - 1, count = 0; i < h && j >= 0 && count < mSpeed; i++, j--, count++) {
                    int nRow = i;
                    int nCol = j;
                    int value = room.curGrids[nRow][nCol];
                    if (checkAddToCanMovedPosList(canMovedPosList, nRow, nCol, value)) {
                        break;
                    }
                }
                //向右下搜索
                for (int i = pRow + 1, j = pCol + 1, count = 0; i < h && j < w && count < mSpeed; i++, j++, count++) {
                    int nRow = i;
                    int nCol = j;
                    int value = room.curGrids[nRow][nCol];
                    if (checkAddToCanMovedPosList(canMovedPosList, nRow, nCol, value)) {
                        break;
                    }
                }
            }
            return canMovedPosList;
        }

    }
}
